Check queue readiness and capacity before waiting - #132
Conversation
|
Opportunistically trying to get the grant seems like a good idea, ye. I kinda wonder why that wasn't the case before/why maitake doesn't do that by itself. This section in
(In particular whether this case is relevant for |
`FramedProducer::wait_grant` and `StreamProducer::wait_grant_exact` park until a request can be met, but a request larger than the buffer itself cannot be met by any amount of consumer progress. Both documented that as "will never return" and left the caller hung on a size the queue could have rejected outright. The synchronous `grant` and `grant_exact` already answer this exact input with `WriteGrantError::InsufficientSize`, so the waiting variants now return the same `Result` rather than growing a second convention for the same condition. The capacity comparison happens once, before the wait: capacity is fixed for the lifetime of the queue, so a request that does not fit an empty buffer will never fit a fuller one. `wait_grant_max_remaining` is unaffected; it caps its ask at what is available.
|
The race that doc warns about is check-then-register without a re-check. Maitake can't do the same because it only sees an arbitrary closure. |
Summary
Two guards on the async wait paths, one commit each.
The first attempts framed and stream queue operations before entering the async notifier. When the queue is not ready, the methods retain the existing notifier path, including its subscribe-before-recheck ordering. This avoids waker registration and notifier bookkeeping when a grant or frame is already available. A counting notifier test covers every async wait method without relying on timing.
The second handles the case the first cannot: a request larger than the buffer itself.
FramedProducer::wait_grantandStreamProducer::wait_grant_exactdocumented that as "will never return" and parked forever on a size no amount of consumer progress can satisfy. Both now compare against capacity up front and returnWriteGrantError::InsufficientSize, which is what the synchronousgrantandgrant_exactalready answer for the same input rather than a second convention for the same condition. Capacity is fixed for the life of the queue, so the comparison happens once, before the wait.wait_grant_max_remainingis unaffected; it caps its ask at what is available.That second commit changes
wait_grantandwait_grant_exactto returnResult, so it is an API break. Happy to split it back out if you would rather take the readiness check on its own.#133 touches this same file, but the only overlap is that both append a test module at the end of
framed.rs— whichever lands second needs a keep-both resolution, not a semantic one.Testing
cargo test --features=stdcargo build --no-default-featurescargo build --features=stdcargo build --no-default-features --target=thumbv6m-none-eabicargo build --target=thumbv6m-none-eabi --features=portable-atomic-unsafe-assume-single-core./miri.shcargo clippy --features=std --all-targets -- -D warnings